3900 // Buffer cache.
3901 //
3902 // The buffer cache is a linked list of buf structures holding
3903 // cached copies of disk block contents.  Caching disk blocks
3904 // in memory reduces the number of disk reads and also provides
3905 // a synchronization point for disk blocks used by multiple processes.
3906 //
3907 // Interface:
3908 // * To get a buffer for a particular disk block, call bread.
3909 // * After changing buffer data, call bwrite to flush it to disk.
3910 // * When done with the buffer, call brelse.
3911 // * Do not use the buffer after calling brelse.
3912 // * Only one process at a time can use a buffer,
3913 //     so do not keep them longer than necessary.
3914 //
3915 // The implementation uses three state flags internally:
3916 // * B_BUSY: the block has been returned from bread
3917 //     and has not been passed back to brelse.
3918 // * B_VALID: the buffer data has been initialized
3919 //     with the associated disk block contents.
3920 // * B_DIRTY: the buffer data has been modified
3921 //     and needs to be written to disk.
3922 // hiyush
3923 #include "types.h"
3924 #include "defs.h"
3925 #include "param.h"
3926 #include "spinlock.h"
3927 #include "buf.h"
3928 
3929 struct {
3930   struct spinlock lock;
3931   struct buf buf[NBUF];
3932 
3933   // Linked list of all buffers, through prev/next.
3934   // head.next is most recently used.
3935   struct buf head;
3936 } bcache;
3937 
3938 void
3939 binit(void)
3940 {
3941   struct buf *b;
3942 
3943   initlock(&bcache.lock, "bcache");
3944 
3945   // Create linked list of buffers
3946   bcache.head.prev = &bcache.head;
3947   bcache.head.next = &bcache.head;
3948   for(b = bcache.buf; b < bcache.buf+NBUF; b++){
3949     b->next = bcache.head.next;
3950     b->prev = &bcache.head;
3951     b->dev = -1;
3952     bcache.head.next->prev = b;
3953     bcache.head.next = b;
3954   }
3955 }
3956 
3957 // Look through buffer cache for sector on device dev.
3958 // If not found, allocate fresh block.
3959 // In either case, return locked buffer.
3960 static struct buf*
3961 bget(uint dev, uint sector)
3962 {
3963   struct buf *b;
3964 
3965   acquire(&bcache.lock);
3966 
3967  loop:
3968   // Try for cached block.
3969   for(b = bcache.head.next; b != &bcache.head; b = b->next){
3970     if(b->dev == dev && b->sector == sector){
3971       if(!(b->flags & B_BUSY)){
3972         b->flags |= B_BUSY;
3973         release(&bcache.lock);
3974         return b;
3975       }
3976       sleep(b, &bcache.lock);
3977       goto loop;
3978     }
3979   }
3980 
3981   // Allocate fresh block.
3982   for(b = bcache.head.prev; b != &bcache.head; b = b->prev){
3983     if((b->flags & B_BUSY) == 0){
3984       b->dev = dev;
3985       b->sector = sector;
3986       b->flags = B_BUSY;
3987       release(&bcache.lock);
3988       return b;
3989     }
3990   }
3991   panic("bget: no buffers");
3992 }
3993 
3994 
3995 
3996 
3997 
3998 
3999 
4000 // Return a B_BUSY buf with the contents of the indicated disk sector.
4001 struct buf*
4002 bread(uint dev, uint sector)
4003 {
4004   struct buf *b;
4005 
4006   b = bget(dev, sector);
4007   if(!(b->flags & B_VALID))
4008     iderw(b);
4009   return b;
4010 }
4011 
4012 // Write b's contents to disk.  Must be locked.
4013 void
4014 bwrite(struct buf *b)
4015 {
4016   if((b->flags & B_BUSY) == 0)
4017     panic("bwrite");
4018   b->flags |= B_DIRTY;
4019   iderw(b);
4020 }
4021 
4022 // Release the buffer b.
4023 void
4024 brelse(struct buf *b)
4025 {
4026   if((b->flags & B_BUSY) == 0)
4027     panic("brelse");
4028 
4029   acquire(&bcache.lock);
4030 
4031   b->next->prev = b->prev;
4032   b->prev->next = b->next;
4033   b->next = bcache.head.next;
4034   b->prev = &bcache.head;
4035   bcache.head.next->prev = b;
4036   bcache.head.next = b;
4037 
4038   b->flags &= ~B_BUSY;
4039   wakeup(b);
4040 
4041   release(&bcache.lock);
4042 }
4043 
4044 
4045 
4046 
4047 
4048 
4049 
